package org.bookshare.validator.report;

import java.util.List;
import java.util.Map;

import org.benetech.beans.error.ValidationError;
import org.benetech.beans.error.ValidationError.Severity;
import org.benetech.collections.ListMap;
import org.benetech.util.XMLParseUtils;
import org.bookshare.document.beans.HasXML;
import org.jdom.Document;
import org.jdom.Element;

/**
 * Report generator that produces statistics about the content.
 * @author Reuben Firmin
 */
public final class StatisticsReportGenerator implements ReportGenerator {

	/**
	 * Default constructor.
	 *
	 */
	public StatisticsReportGenerator() {
		// empty
	}
    /**
     * {@inheritDoc}
     */
    public void addToReport(final ValidationMetadata report) {
    	final Map<String, Object> stats = report.getModelMap();
        stats.put("totalErrors", (Integer) report.getDocumentViolations()
                .getTotalSize() + (Integer) report.getElementViolations()
                .getTotalSize());
        stats.put("totalErrorErrors", getNumErrorsAt(Severity.ERROR,
                report.getDocumentViolations(), report.getElementViolations()));
        stats.put("totalWarningErrors", getNumErrorsAt(
                Severity.WARNING,
                report.getDocumentViolations(), report.getElementViolations()));
        stats.put("totalInfoErrors", getNumErrorsAt(
                Severity.INFO,
                report.getDocumentViolations(), report.getElementViolations()));
        stats.put("totalExceptions", report.getExceptions().size());
        stats.put("totalSections", XMLParseUtils.getTotalElements(
        		((HasXML)report.getDocumentSet()).getXMLDocument(), "level1"));
        stats.put("totalPages", XMLParseUtils.getTotalElements(
                ((HasXML)report.getDocumentSet()).getXMLDocument(), "pagenum"));
    }

    /**
     * Calculate the total number of errors at a given severity level.
     * @param severity The severity level
     * @param documentViolations The document violations map
     * @param elementViolations The element violations map
     * @return never null
     */
    private Integer getNumErrorsAt(final Severity severity,
            final ListMap<Document, ValidationError> documentViolations,
            final ListMap<Element, ValidationError> elementViolations)
    {
        return getNumErrorsAt(severity, documentViolations)
            + getNumErrorsAt(severity, elementViolations);
    }

    /**
     * Get the number of errors at a given severity level.
     * @param severity The severity level
     * @param violationMap A given violation map
     * @return never null
     */
    private Integer getNumErrorsAt(final Severity severity,
            final ListMap< ? , ValidationError> violationMap)
    {
        int count = 0;
        for (List<ValidationError> violations : violationMap.values()) {
            for (ValidationError violation : violations) {
                if (violation.getSeverity().equals(severity)) {
                    count++;
                }
            }
        }
        return count;
    }

    /**
     * {@inheritDoc}
     */
    public String getModelKey() {
        return "statistics";
    }

}
